﻿

using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Abp.Linq;
using Abp.Linq.Extensions;
using Abp.Extensions;
using Abp.UI;
using Abp.Domain.Repositories;
using Abp.Domain.Services;

using LZ.DCode;
using LZ.DCode.DataDictionarys;
using LZ.DCode.Dtos;
using LZ.DCode.DataDictionarys.Dtos;
using Abp.Threading;

namespace LZ.DCode.DataDictionarys.DomainService
{
    /// <summary>
    /// DataDictionary领域层的业务管理
    ///</summary>
    public class DataDictionaryManager :DCodeDomainServiceBase, IDataDictionaryManager
    {
		
		private readonly IRepository<DataDictionary,int> _repository;
        private readonly IRepository<DataGroup> _dataGroupRepository;

        private const int TreeRootId = 0;

        /// <summary>
        /// DataDictionary的构造方法
        ///</summary>
        public DataDictionaryManager(
			IRepository<DataDictionary, int> repository
		)
		{
			_repository =  repository;
		}


		/// <summary>
		/// 初始化
		///</summary>
		public void InitDataDictionary()
		{
			throw new NotImplementedException();
		}

        #region 接口方法


        public async Task<List<DataGroupList>> GetDataGroupListAsync(string groupCode)
        {
            var query = from r in _repository.GetAll()
                        join g in _dataGroupRepository.GetAll() on r.Group equals g.Id
                        where g.Code == groupCode
                        select new DataGroupList()
                        {
                            Id = r.Id,
                            Code = r.Code,
                            Name = r.Desc,
                            Value = r.Value,
                            Seq = r.Seq
                        };
            var result = await query.OrderBy(q => q.Seq).AsNoTracking().ToListAsync();
            return result;
        }

        public List<DataGroupList> GetDataGroupListCache(string groupCode)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await GetDataGroupListAsync(groupCode);
            });
        }

        public async Task<List<string>> GetDataGroupArrayAsync(string groupCode, string code)
        {
            var treeList = await GetDataGroupTreeListAsync(groupCode);
            var Data = treeList.Where(t => t.Code == code).ToList();
            List<string> groupArray = new List<string>();
            groupArray.Add(code);
            if (Data.Count > 0)
            {
                GetGroupArray(groupArray, treeList, Data[0].Id);
            }
            return groupArray;
        }

        public List<string> GetDataGroupArrayCache(string groupCode, string code)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await GetDataGroupArrayAsync(groupCode, code);
            });
        }

        public async Task<List<NzTreeNode>> GetDataGroupNzTreeAsync(string groupCode, string selectCode = null)
        {
            var treeList = await GetDataGroupTreeListAsync(groupCode);
            var pcodes = new List<string>();
            //没有选中的，就默认选中第一个
            if (selectCode == null && treeList.Any(t => t.ParentId == 0))
            {
                var select = treeList.Where(t => t.ParentId == 0).OrderBy(t => t.Seq).First();
                selectCode = select.Code;
                pcodes = GetParentCodes(treeList, select.ParentId);
            }
            else if (treeList.Any(t => t.Code == selectCode))
            {
                var select = treeList.Where(t => t.Code == selectCode).OrderBy(t => t.Seq).First();
                pcodes = GetParentCodes(treeList, select.ParentId);
            }

            var result = GetTreeList(treeList, TreeRootId, selectCode, pcodes);

            return result;
        }

        public List<NzTreeNode> GetDataGroupNzTreeCache(string groupCode, string selectCode = null)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await GetDataGroupNzTreeAsync(groupCode, selectCode);
            });
        }

        public async Task<List<DataGroupTreeList>> GetDataGroupTreeListAsync(string groupCode)
        {
            var query = from r in _repository.GetAll()
                        join g in _dataGroupRepository.GetAll() on r.Group equals g.Id
                        where g.Code == groupCode
                        && g.Mode == DataGroupModeEnum.Tree
                        select new DataGroupTreeList()
                        {
                            Id = r.Id,
                            Code = r.Code,
                            Name = r.Desc,
                            ParentId = r.ParentId,
                            Seq = r.Seq
                        };
            var result = await query.OrderBy(q => q.Seq).AsNoTracking().ToListAsync();
            return result;
        }

        public List<DataGroupTreeList> GetDataGroupTreeListCache(string groupCode)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await GetDataGroupTreeListAsync(groupCode);
            });
        }

        public async Task<string> GetDataValueAsync(string groupCode, string code, string defaultValue)
        {
            var query = from r in _repository.GetAll()
                        join g in _dataGroupRepository.GetAll() on r.Group equals g.Id
                        where g.Code == groupCode
                        && r.Code == code
                        && g.Mode == DataGroupModeEnum.Value
                        select r.Value;
            var result = await query.AsNoTracking().FirstOrDefaultAsync();
            if (result == null)
            {
                return defaultValue;
            }
            return result;
        }

        public string GetDataValueCache(string groupCode, string code, string defaultValue)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await GetDataValueAsync(groupCode, code, defaultValue);
            });
        }

        public async Task<bool> CheckDataAsync(string groupCode, string code)
        {
            var querey = from r in _repository.GetAll()
                         join g in _dataGroupRepository.GetAll() on r.Group equals g.Id
                         where g.Code == groupCode
                         && r.Code == code
                         select r;
            var bo = await querey.AnyAsync();
            return bo;
        }

        public bool CheckDataCache(string groupCode, string code)
        {
            return AsyncHelper.RunSync(async () =>
            {
                return await CheckDataAsync(groupCode, code);
            });
        }

        public async Task TreeUpgradeAsync(int id)
        {
            var node = await _repository.GetAsync(id);
            if (node.ParentId == 0)
            {
                throw new UserFriendlyException("当前节点已经是顶级了，不能再升级");
            }
            var prentNode = await _repository.GetAsync(node.ParentId);
            node.ParentId = prentNode.ParentId;
            node.Seq = prentNode.Seq + 1;
            RefreshCache();
        }

        public async Task TreeDowngradeAsync(int id)
        {
            var node = await _repository.GetAsync(id);
            var preNode = await _repository.GetAll() //找同级上一个节点
                .Where(n => n.Group == node.Group && n.ParentId == node.ParentId && n.Seq < node.Seq)
                .OrderByDescending(n => n.Seq)
                .FirstOrDefaultAsync();

            if (preNode == null)
            {
                throw new UserFriendlyException("当前节点是第一个节点，不能降级，请用转移");
            }

            node.ParentId = preNode.Id;

            RefreshCache();
        }

        public async Task TreeTransferAsync(int id, int parentId)
        {
            if (id == parentId)
            {
                throw new UserFriendlyException("不能转移到自己节点下面");
            }
            var node = await _repository.GetAsync(id);
            node.ParentId = parentId;
        }


        #endregion

        #region 私有方法

        /// <summary>
        /// 递归组件树
        /// </summary>
        private void GetGroupArray(List<string> groupArray, List<DataGroupTreeList> treeList, int pid)
        {

            var dgList = treeList.Where(t => t.ParentId == pid).OrderBy(t => t.Seq).ToList();
            foreach (var item in dgList)
            {
                groupArray.Add(item.Code);
                if (treeList.Any(t => t.ParentId == item.Id)) //是否存在子集
                {

                    GetGroupArray(groupArray, treeList, item.Id);
                }
            }
        }


        private List<NzTreeNode> GetTreeList(List<DataGroupTreeList> treeList, int pid, string selectcode, List<string> parentCodes)
        {
            var tree = new List<NzTreeNode>();
            var dgList = treeList.Where(t => t.ParentId == pid).OrderBy(t => t.Seq).ToList();

            foreach (var item in dgList)
            {
                var node = new NzTreeNode();
                node.key = item.Code;
                node.title = item.Name;
                if (selectcode == item.Code)
                {
                    node.selected = true;
                }
                else
                {
                    node.selected = false;
                }
                if (parentCodes.Contains(item.Code))
                {
                    node.expanded = true;
                }
                else
                {
                    node.expanded = false;
                }

                tree.Add(node);

                if (treeList.Any(t => t.ParentId == item.Id)) //是否存在子集
                {
                    node.isLeaf = false;
                    node.children = GetTreeList(treeList, item.Id, selectcode, parentCodes);
                }
                else
                {
                    node.isLeaf = true;
                }
            }
            return tree;
        }

        private List<string> GetParentCodes(List<DataGroupTreeList> treeList, int pid)
        {
            var codes = new List<string>();
            var parent = treeList.Where(t => t.Id == pid).FirstOrDefault();
            if (parent != null)
            {
                codes.Add(parent.Code);
                var pcodes = GetParentCodes(treeList, parent.ParentId);
                if (pcodes.Count() > 0)
                {
                    codes.AddRange(pcodes);
                }
            }
            return codes;
        }

        private void RefreshCache() { }

        #endregion

    }
}

